import java.io.*;
import java.net.*;
import java.util.*;

public class ServerAgent extends Thread
{
	protected Socket skt = null;
	protected boolean quit = false;
	protected ObjectInputStream oin = null;
	protected ObjectOutputStream oout = null;
	protected boolean mode = FileService.BINARY;
	protected FileService fs = new FileService();
	
	public ServerAgent(Socket s)
	{
		skt = s;
	}
	
	public void run()
	{		
		try
		{
			oout = new ObjectOutputStream(skt.getOutputStream());
			oin = new ObjectInputStream(skt.getInputStream());			
			while (!quit)
			{
				Command cmd = readCommand();
				executeCommand(cmd);
			}
		}
		catch (Exception ex)
		{			quit = true;
			ex.printStackTrace();	
		}
		finally 
		{
			try
			{
				skt.close();
			} 
			catch (Exception ex)
			{				quit = true;
				ex.printStackTrace();
			}
		}
	}
	
	public Command readCommand()
	{
		Command cmd = null;
		
		try
		{
			cmd = (Command)oin.readObject();
		}
		catch (Exception ex)
		{			quit = true;
			ex.printStackTrace();
		}
		
		return cmd;
	}
	
	public void executeCommand(Command cmd)
	{
		if (cmd == null) return;
		
		switch (cmd.commandID)
		{
			case Command.GET:
				get(cmd.commandArg);
				break;
			case Command.MGET:
				mget(cmd.commandArg);
				break;
			case Command.PUT:
				put(cmd.commandArg);
				break;
			case Command.MPUT:
				mput(cmd.commandArg);
				break;
			case Command.BINARY:	
				setMode(FileService.BINARY);
				break;
			case Command.ASCII:
				setMode(FileService.ASCII);
				break;
			case Command.LS:
				ls();
				break;
			case Command.CD:
				cd(cmd.commandArg);
				break;
			case Command.PWD:
				pwd();
				break;
			case Command.MKDIR:
				mkdir(cmd.commandArg);
				break;
			case Command.QUIT:
				quit();
				break;
			default:
				System.out.println("Invalid Command");				
		}
	}
	
	public void sendReply(String reply)
	{
		try 
		{
			oout.writeObject(reply);
			oout.flush();
		}
		catch (Exception ex)
		{			quit = true;
			ex.printStackTrace();
		}
	}
	
	public void get(String args)
	{
		try
		{
			File file = fs.getFileObject(args);	
			FileHeader header = fs.getFileHeader(file);
			oout.writeObject(header);
			oout.flush();
			
			if (file.canRead() && file.isFile())
			{
				if (oin.readBoolean())
				{
					if (mode)
						fs.sendBinaryFile(file, skt);
					else
						fs.sendAsciiFile(file, skt);
				}
			}
		}
		catch (Exception ex)
		{
			quit = true;
			ex.printStackTrace();
		}
	}
	
	public void mget(String args)
	{
		try
		{
			File[] files = fs.matches(args);
			Vector v = new Vector();
			for (int i = 0; i < files.length; i++)
				if (files[i].isFile() && files[i].canRead())
				{
					v.addElement(fs.getFileHeader(files[i]));
				}
			oout.writeObject(v);
			oout.flush();
		}
		catch (Exception ex)
		{
			quit = true;
			ex.printStackTrace();
		}
	}
	
	public void put(String args)
	{
		try
		{
			FileHeader header = (FileHeader)oin.readObject();
			
			if (header.isFile && header.canRead)
			{
				oout.writeBoolean(true);
				oout.flush();
				if (mode)
					fs.receiveBinaryFile(header, skt);
				else
					fs.receiveAsciiFile(header, skt);
			}
		} 
		catch (Exception ex)
		{
			quit = true;
			ex.printStackTrace();
		}
	}
	
	public void mput(String args)
	{
	}
	
	public void setMode(boolean m)
	{
		mode = m;
		sendReply("Server mode set to " + (m ? "binary" : "ascii"));
	}
	
	public void ls()
	{
		StringBuffer buf = new StringBuffer();
		String[] lst = fs.ls();
		
		for (int i = 0; i < lst.length; i++)
			buf.append(lst[i]).append("\n");
		sendReply(buf.toString());
	}
	
	public void cd(String dir)
	{
		fs.cd(dir);
		sendReply("Command CD successful");
	}
	
	public void pwd()
	{
		sendReply(fs.pwd());
	}
	
	public void mkdir(String dir)
	{
		fs.mkdir(dir);
		sendReply("Command MKDIR sucessful");
	}
	
	public void quit()
	{
		quit = true;		System.out.println(skt.getInetAddress() + " terminated");
		sendReply("Connection terminated");
	}
}
